﻿using Cysharp.Threading.Tasks;
using Net.Client;
using Net.Event;
using Net.Share;
using Net.System;

namespace ClientStressTesting
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource cts;
        private bool run;
        private readonly List<ClientBase> clients = new();

        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            NDebug.BindLogAll((log) =>
            {
                toolStripStatusLabel1.Text = log;
            });
            Application.ThreadExit += new EventHandler((o, e) =>
            {
                if (clients != null)
                {
                    for (int i = 0; i < clients.Count; i++)
                        clients[i].Close(false);
                }
            });
        }

        public ThreadPipeline<TcpClient> threadPipeline = new();

        private void button1_Click(object sender, EventArgs e)
        {
            _ = Test();
        }

        private async UniTaskVoid Test()
        {
            run = !run;
            if (!run)
            {
                cts?.Cancel();
                cts?.Dispose();
                foreach (var client in clients)
                {
                    client.Close(false);
                }
                clients.Clear();
                threadPipeline.Dispose();
                button1.Text = "启动";
            }
            else
            {
                dataGridView1.Rows.Clear();
                var ip = textBox2.Text;
                var port = int.Parse(textBox3.Text);
                var cliNum = int.Parse(textBox4.Text);
                var dataLen = int.Parse(textBox1.Text);
                var ms = int.Parse(textBox5.Text);
                cts = new CancellationTokenSource();
                threadPipeline.Init("NetworkHandler_");
                var clients = new List<UniTask<bool>>();
                for (int i = 0; i < cliNum; i++)
                {
                    var client = new TcpClient();
                    client.Config.SendBufferSize = 1024;
                    client.Config.ReceiveBufferSize = 1024;
                    client.AddAdapter(new Net.Adapter.SerializeAdapter3());
                    var row = dataGridView1.Rows.Add();
                    client.OnNetworkDataTraffic = (df) =>
                    {
                        dataGridView1.Rows[row].HeaderCell.Value = row.ToString();
                        dataGridView1.Rows[row].Cells[0].Value = client.UserId;
                        dataGridView1.Rows[row].Cells[1].Value = df.SentBytesPerSecond;
                        dataGridView1.Rows[row].Cells[2].Value = df.ReceivedBytesPerSecond;
                        dataGridView1.Rows[row].Cells[3].Value = df.SentPacketsPerSecond;
                        dataGridView1.Rows[row].Cells[4].Value = df.ReceivedPacketsPerSecond;
                        dataGridView1.Rows[row].Cells[5].Value = df.RpcResolveCount;
                        dataGridView1.Rows[row].Cells[6].Value = df.FrameRate;
                        client.Ping();
                    };
                    client.OnPingCallback = (delay) =>
                    {
                        dataGridView1.Rows[row].Cells[7].Value = delay;
                    };
                    client.UpdateMode = NetworkUpdateMode.Custom;
                    threadPipeline.AddWorker(client);
                    clients.Add(client.Connect(ip, port));
                    this.clients.Add(client);
                }
                await UniTask.WhenAll(clients);
                threadPipeline.OnProcess = (group) =>
                {
                    var timer = new TimerTick();
                    while (!cts.IsCancellationRequested)
                    {
                        bool canSend = false;
                        var tick = (uint)Environment.TickCount;
                        if (timer.CheckTimeout(tick, (uint)ms, true))
                        {
                            canSend = true;
                        }
                        for (int i = 0; i < group.Workers.Count; i++)
                        {
                            var client = group.Workers[i];
                            client.Update();
                            if (canSend)
                            {
                                client.Call(NetCmd.Local, new byte[dataLen]);
                            }
                        }
                    }
                };
                threadPipeline.Start();
                button1.Text = "关闭";
            }
        }
    }
}
